﻿using System;
using System.Data;
using System.Xml;

namespace UwaySoft.EsheetServer.DataLayer
{
    public abstract class SqlHelper<TParameter> : ISqlHelper where TParameter : IDataParameter
    {
        #region 构造函数

        protected SqlHelper(string connectString)
        {
            ConnectionString = connectString;
        }

        ~SqlHelper()
        {
            Dispose();
        }

        #endregion

        #region 公共方法

        protected virtual string ConvertCommand(string commandText)
        {
            if(commandText == null)
                throw new ArgumentNullException("commandText");
            return commandText;
        }

        protected virtual TParameter[] ConvertParameter(IParameter[] parameters)
        {
            if(parameters == null)
                throw new ArgumentNullException("parameters");

            var newParameters = new TParameter[parameters.Length];

            for(var i=0; i<newParameters.Length; i++)
            {
                var param = parameters[i] as IParameterContainer<TParameter>;
                if(param == null)
                    throw new ArgumentException(
                        string.Format("数组元素类型出错，IParameterContainer<{0}>类型无法转换为{1}",
                                      typeof (TParameter).Name,
                                      param == null ? "null" : param.GetType().Name));
                newParameters[i] = param.RawParameter;
            }

            return newParameters;
        }

        protected virtual T ConvertScalar<T>(object scalar)
        {
            if (scalar == null || (scalar == DBNull.Value && !typeof(T).IsAssignableFrom(typeof(DBNull))))
                return default(T);

            switch (typeof(T).FullName)
            {
                case "System.Int32": return (T)(object)int.Parse(scalar.ToString());
                case "System.Int64": return (T)(object)long.Parse(scalar.ToString());
                default: return (T)scalar;
            }
        }

        protected virtual void Dispose()
        { }

        #endregion

        #region 抽象方法

        protected abstract int ExecuteNonQuery(string commandText, params TParameter[] parameters);
        protected abstract object ExecuteScalar(string commandText, params TParameter[] parameters);
        protected abstract IRecordReader ExecuteReader(string commandText, params TParameter[] parameters);
        protected abstract DataSet ExecuteDateSet(string commandText, params TParameter[] parameters);

        #endregion

        #region ISqlHelper 成员

        public string ConnectionString { get; private set; }

        public abstract IParameter CreateParameter(string name, object value);

        public int ExecuteNonQuery(string commandText, params IParameter[] parameters)
        {
            var newComandText = ConvertCommand(commandText);
            var newParameter = ConvertParameter(parameters);
            return ExecuteNonQuery(newComandText, newParameter);
        }

        public TScalar ExecuteScalar<TScalar>(string commandText, params IParameter[] parameters)
        {
            var newCommandText = ConvertCommand(commandText);
            var newParameter = ConvertParameter(parameters);
            return ConvertScalar<TScalar>(ExecuteScalar(newCommandText, newParameter));
        }

        public IRecordReader ExecuteReader(string commandText, params IParameter[] parameters)
        {
            var newCommandText = ConvertCommand(commandText);
            var newParameter = ConvertParameter(parameters);
            return ExecuteReader(newCommandText, newParameter);
        }

        public XmlReader ExecuteXmlReader(string commandText, params IParameter[] parameters)
        {
            var newCommandText = ConvertCommand(commandText);
            var newParameter = ConvertParameter(parameters);
            return ExecuteXmlReader(newCommandText, newParameter);
        }

        protected virtual XmlReader ExecuteXmlReader(string commandText, TParameter[] parameters)
        {
            var xmlString = (string) ExecuteScalar(commandText, parameters);
            if (xmlString == null)
                throw new ArgumentNullException("查询返回值为空");
            return XmlReader.Create(new System.IO.StringReader(xmlString));
        }

        public DataSet ExecuteDateSet(string commandText, params IParameter[] parameters)
        {
            var newCommandText = ConvertCommand(commandText);
            var newParameter = ConvertParameter(parameters);
            return ExecuteDateSet(newCommandText, newParameter);
        }

        #endregion
    }
}
